﻿using IoTClient.Clients.PLC;
using IoTClient.Enums;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using TXK.CommonBase;
using Newtonsoft.Json;
using System.IO;
using MiniExcelLibs;

namespace TXK
{
    public class DevXMZ : ScoketDevBase
    {
        #region 属性
        #region 集合
        /// <summary>
        /// 所有的变量
        /// </summary>
        public List<SiemensVar> VariableAll { get; set; } = new();
        /// <summary>
        /// 当前激活的变量 key为VarName
        /// </summary>
        public Dictionary<string, SiemensVar> CurrentVarListByVarName { get; set; } = new();
        /// <summary>
        /// 当前激活的变量 key为Adreess
        /// </summary>
        public Dictionary<string, SiemensVar> CurrentVarListByAddress { get; set; } = new();
        /// <summary>
        /// 通讯组集合(根据存储区进行分组)
        /// </summary>
        public IEnumerable<IGrouping<StoreType, SiemensVar>> VariableGroups { get; set; }

        /// <summary>
        /// 归档(需要报警的,需要记录数据的)变量字典集合
        /// </summary>
        public List<SiemensVar> VariableArchiveList { get; set; } = new();
        /// <summary>
        /// 报警(需要报警的,需要记录数据的)变量字典集合
        /// </summary>
        public List<SiemensVar> VariableAlarmList { get; set; } = new();
        /// <summary>
        /// 为Iot通讯库多组通讯读取准备的变量地址集合
        /// </summary>
        public Dictionary<string, DataTypeEnum> AddresssForIot { get; private set; } = new();
        #endregion

        SiemensS7 s7 = new SiemensS7();
        SiemensClient client = new SiemensClient(IoTClient.Common.Enums.SiemensVersion.S7_1200, new IPEndPoint(IPAddress.Parse("192.168.0.120"), 102));
        public CpuType SiemensCpuType { get; set; }

        public object this[string index]
        {
            get
            {
                if (CurrentValueListByVarName.ContainsKey(index))
                {
                    return CurrentValueListByVarName[index];
                }
                else if (CurrentValueListByAddress.ContainsKey(index))
                {
                    return CurrentValueListByAddress[index];
                }
                else
                {
                    return "没有这个变量";
                }
            }
            set { /* set the specified index to value here */ }
        }
        public DevXMZ()
        {
            s7.MaxPDUSize = MaxPDUSize;
            s7.ConnectTimeOut = ConnectTimeOut;
            s7.ReceiveTimeOut = ReceiveTimeOut;
        }
        public short MaxPDUSize { get; set; } = 240;
        public int ConnectTimeOut { get; set; } = 2000;
        public int ReceiveTimeOut { get; set; } = 2000;
        /// <summary>
        /// 机架号
        /// </summary>
        public int Rack { get; set; }
        /// <summary>
        /// 插槽号
        /// </summary>
        public int Slot { get; set; }

        /// <summary>
        /// 是否启用多组读取
        /// </summary>
        public bool IsUseMultiRead { get; set; } = true;
        #endregion
        public override void Start()
        {
            Init();
            Task.Run(() =>
            {
                ConnectAndReadValue();

            }, cts.Token);
        }
        #region MyRegion


        /// <summary>
        /// 连接并读取数据
        /// </summary>
        private void ConnectAndReadValue()
        {
            while (!cts.IsCancellationRequested)
            {
                //判断是否连接,没有连接,则执行连接程序
                // if (true)
                if (IsConnected)
                {
                    this.sw.Restart();
                    //不是多组读取
                    if (!this.IsUseMultiRead)
                    {
                        #region MyRegion
                        //foreach (var deviceGroup in this.VariableAll)
                        //{
                        //    if (!deviceGroup.IsActive)
                        //    {
                        //        continue;
                        //    }
                        //    byte[] array;
                        //    array = this.s7.ReadBytes(this.GetStoreTypeByStoreArea(deviceGroup.StoreArea), deviceGroup.DBNo, deviceGroup.Start, deviceGroup.Length);
                        //    if (array != null && array.Length == deviceGroup.Length)
                        //    {
                        //        base.ErrorTimes = 0;
                        //        foreach (SiemensVariable var in deviceGroup.varList)
                        //        {
                        //            if (!this.VerifySiemensAddress(var.Start, out var start, out var offset))
                        //            {
                        //                continue;
                        //            }
                        //            start -= deviceGroup.Start;
                        //            switch (var.VarType)
                        //            {
                        //                case DataType.Bool:
                        //                    var.Value = BitLib.GetBitFromByteArray(array, start, offset);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Byte:
                        //                    var.Value = ByteLib.GetByteFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.UShort:
                        //                    var.Value = UShortLib.GetUShortFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Short:
                        //                    var.Value = ShortLib.GetShortFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.UInt:
                        //                    var.Value = UIntLib.GetUIntFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Int:
                        //                    var.Value = IntLib.GetIntFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Long:
                        //                    var.Value = LongLib.GetLongFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.ULong:
                        //                    var.Value = ULongLib.GetULongFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Float:
                        //                    var.Value = FloatLib.GetFloatFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Double:
                        //                    var.Value = DoubleLib.GetDoubleFromByteArray(array, start);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.HexString:
                        //                    if (var.Start.Contains('.'))
                        //                    {
                        //                        var.Value = StringLib.GetHexStringFromByteArray(array, start, offset);
                        //                    }
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.ByteArray:
                        //                    if (var.Start.Contains('.'))
                        //                    {
                        //                        var.Value = ByteArrayLib.GetByteArray(array, start, offset);
                        //                    }
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.String:
                        //                    if (var.Start.Contains('.'))
                        //                    {
                        //                        var.Value = StringLib.GetSiemensStringFromByteArray(array, start, offset);
                        //                    }
                        //                    else
                        //                    {
                        //                        var.Value = StringLib.GetStringFromByteArray(array, start, offset, Encoding.GetEncoding("GBK"));
                        //                    }
                        //                   return DataTypeEnum.Bool;
                        //            }
                        //            var.Value = MigrationLib.GetMigrationValue(var.Value, var.Scale, var.Offset);
                        //            base.UpdateCurrentValue(var);
                        //        }
                        //    }
                        //    else
                        //    {
                        //        base.ErrorTimes++;
                        //        if (base.ErrorTimes >= base.MaxErrorTimes)
                        //        {
                        //            this.IsConnected = false;
                        //        }
                        //    }
                        //}
                        #endregion

                    }
                    //是多组读取
                    else
                    {
                        try
                        {

                            CurrentValueListByAddress = client.BatchRead(AddresssForIot).Value;
                            foreach (var variable in VariableAll)
                            {
                                var address = variable.VarAddress.ToUpper().ToString();
                                var value = CurrentValueListByAddress[address].ToString();
                                variable.Value = value;
                                CheckAlarm(variable, value);
                            }
                        }
                        catch (Exception ex)
                        {

                            ;
                        }
                        if (true)
                        {
                            base.ErrorTimes++;
                            if (base.ErrorTimes >= base.MaxErrorTimes)
                            {
                                this.IsConnected = false;
                            }
                        }

                        #region MyRegion
                        //foreach (SiemensDeviceGroup deviceGroup2 in this.DeviceGroupList)
                        //{
                        //    byte[] value;
                        //    value = deviceGroup2.Value;
                        //    if (value != null && value.Length == deviceGroup2.Length)
                        //    {
                        //        base.ErrorTimes = 0;
                        //        foreach (SiemensVariable var2 in deviceGroup2.varList)
                        //        {
                        //            if (!this.VerifySiemensAddress(var2.Start, out var start2, out var offset2))
                        //            {
                        //                continue;
                        //            }
                        //            start2 -= deviceGroup2.Start;
                        //            switch (var2.VarType)
                        //            {
                        //                case DataType.Bool:
                        //                    var2.Value = BitLib.GetBitFromByteArray(value, start2, offset2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Byte:
                        //                    var2.Value = ByteLib.GetByteFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.UShort:
                        //                    var2.Value = UShortLib.GetUShortFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Short:
                        //                    var2.Value = ShortLib.GetShortFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.UInt:
                        //                    var2.Value = UIntLib.GetUIntFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Int:
                        //                    var2.Value = IntLib.GetIntFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Long:
                        //                    var2.Value = LongLib.GetLongFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.ULong:
                        //                    var2.Value = ULongLib.GetULongFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Float:
                        //                    var2.Value = FloatLib.GetFloatFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.Double:
                        //                    var2.Value = DoubleLib.GetDoubleFromByteArray(value, start2);
                        //                   return DataTypeEnum.Bool;
                        //                case DataType.String:
                        //                    if (var2.Start.Contains('.'))
                        //                    {
                        //                        var2.Value = StringLib.GetSiemensStringFromByteArray(value, start2, offset2);
                        //                    }
                        //                    else
                        //                    {
                        //                        var2.Value = StringLib.GetStringFromByteArray(value, start2, offset2, Encoding.GetEncoding("GBK"));
                        //                    }
                        //                   return DataTypeEnum.Bool;
                        //            }
                        //            var2.Value = MigrationLib.GetMigrationValue(var2.Value, var2.Scale, var2.Offset);
                        //            base.UpdateCurrentValue(var2);
                        //        }
                        //    }
                        //    else
                        //    {
                        //        base.ErrorTimes++;
                        //        if (base.ErrorTimes >= base.MaxErrorTimes)
                        //        {
                        //            this.IsConnected = false;
                        //        }
                        //    }
                        //}
                        #endregion
                    }
                    //读取失败
                    //else
                    //{
                    //    base.ErrorTimes++;
                    //    if (base.ErrorTimes >= base.MaxErrorTimes)
                    //    {
                    //        this.IsConnected = false;
                    //    }
                    //}
                    CycleTime = sw.ElapsedMilliseconds;

                }
                else
                {
                    //判断是否是第一次连接
                    if (FirstConnect)
                    {
                        //this.s7.ConnectTimeOut = ConnectTimeOut;
                        FirstConnect = false;
                    }
                    else
                    {
                        Thread.Sleep(ReConnectTime);
                        //1.先断开连接
                        // s7.DisConnect();
                        client.Close();
                    }
                    this.IsConnected = client.Open().IsSucceed;
                }

            }
        }


        #region 根据变量的数据类型转化为通讯库需要的数据类型
        /// <summary>
        /// 根据变量的数据类型转化为通讯库需要的数据类型
        /// </summary>
        /// <returns></returns>
        private void GetVarlistByVarType()
        {
            AddresssForIot = VariableAll.ToDictionary(x => x.VarAddress, x => GetDataType(x.DataType));
        }
        /// <summary>
        /// 将数据类型转化为Iot通讯库需要的数据类型
        /// </summary>
        /// <param name="dataType"></param>
        /// <returns></returns>
        private DataTypeEnum GetDataType(DataType dataType)
        {
            switch (dataType)
            {
                case DataType.Bool:
                    return DataTypeEnum.Bool;
                case DataType.Byte:
                    return DataTypeEnum.Byte;
                case DataType.Short:
                    return DataTypeEnum.Int16;
                case DataType.UShort:
                    return DataTypeEnum.UInt16;
                case DataType.Int:
                    return DataTypeEnum.Int32;
                case DataType.UInt:
                    return DataTypeEnum.UInt32;
                case DataType.Float:
                    return DataTypeEnum.Float;
                case DataType.Double:
                    return DataTypeEnum.Double;
                case DataType.Long:
                    return DataTypeEnum.Int64;
                case DataType.ULong:
                    return DataTypeEnum.UInt64;
                case DataType.String:
                    return DataTypeEnum.None;
                case DataType.ByteArray:
                    return DataTypeEnum.None;
                case DataType.HexString:
                    return DataTypeEnum.None;
            }
            return DataTypeEnum.Double;
        }

        #endregion
        #endregion
        #region 变量导入导出

        public void SaveAsJson(string path = null)
        {
            FileStream fs = new FileStream("json.json", FileMode.Create);
            var str = JsonConvert.SerializeObject(this);
            StreamWriter sw = new StreamWriter(fs);
            sw.Write(str);
            sw.Close();
            fs.Close();
            // JsonConvert.
            // JsonConvert.DeserializeObject(str);
            //VariableAll = null;
        }
        public void SaveAsExcel(string path = null)
        {
            MiniExcel.SaveAs("text.xlsx", this.VariableAll);
        }
        public void SaveAsCsv(string path = null)
        {
            MiniExcel.SaveAs("text.xlsx", this.VariableAll);
        }
        public void LoadConFigByJson(string path)
        {
            //FileStream
            var str = JsonConvert.SerializeObject(this);

            JsonConvert.DeserializeObject(str);
            VariableAll = null;
        }
        public void LoadConFigByExcel(string path = null)
        {
            path = path == null ? "varlist.xlsx" : path;
            this.VariableAll = MiniExcel.Query<SiemensVar>(path).ToList();
        }
        public void LoadConFigByCsv(string path = null)
        {
            this.VariableAll = MiniExcel.Query<SiemensVar>("Variables.csv").ToList();
        }
        public void LoadConFigByXml(string path)
        {
            VariableAll = null;
        }
        public void LoadConFigByIni(string path)
        {
            VariableAll = null;
        }

        #endregion
        /// <summary>
        /// 初始化
        /// </summary>
        public new void Init()
        {
            this.VariableArchiveList = VariableAll.Where(x => x.ArchiveEnable == true).ToList();//归档变量集合
            this.VariableAlarmList = VariableAll.Where(x => x.AlarmEnable == true).ToList();    //报警变量集合
            this.CurrentValueListByVarName = VariableAll.ToDictionary(x => x.VarName.ToUpper(), x => x.Value);   //当前变量的Value集合
            this.CurrentValueListByAddress = VariableAll.ToDictionary(x => x.VarAddress.ToUpper(), x => x.Value);//当前变量的Value集合
            this.CurrentVarListByVarName = VariableAll.ToDictionary(x => x.VarName.ToUpper());
            this.CurrentVarListByAddress = VariableAll.ToDictionary(x => x.VarAddress.ToUpper());

            GetVarlistByVarType();
        }

    }
}
